package com.tnsw.facebookautoliker;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;

import org.json.JSONArray;
import org.json.JSONObject;

import com.facebook.FacebookOperationCanceledException;
import com.facebook.HttpMethod;
import com.facebook.LoggingBehavior;
import com.facebook.Request;
import com.facebook.RequestAsyncTask;
import com.facebook.Response;
import com.facebook.Session;
import com.facebook.SessionState;
import com.facebook.Settings;
import com.facebook.Session.NewPermissionsRequest;
import com.facebook.internal.SessionTracker;
import com.facebook.model.GraphUser;
import com.tnsw.coreutils.MyLog;
import com.tnsw.coreutils.MyUncaughtExceptionHandler;
import com.tnsw.coreutils.StaticConfig;
import com.tnsw.coreutils.database.DBManagerBase;
import com.tnsw.coreutils.database.RecordBase;
import com.tnsw.coreutils.files.FileUtils;
import com.tnsw.coreutils.queuemanager.QDelegateManager;
import com.tnsw.coreutils.text.TextUtils;
import com.tnsw.facebookautoliker.database.DBManager;
import com.tnsw.facebookautoliker.database.FriendsPost;
import com.tnsw.facebookautoliker.helper.FacebookBGManager;
import com.tnsw.facebookautoliker.helper.GeneralManager;
import com.tnsw.facebookautoliker.services.AutoLikerService;

import android.os.Build;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.util.Log;
import android.util.Base64;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.SearchView;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener, Session.StatusCallback {

	public static boolean IS_INITIALZED = false;
	
	private String[] requiredReadPermission = {"email", "read_stream", "friends_birthday", "read_friendlists", "friends_photos", "user_photos", "friends_actions:getpath"};
	private String[] requiredPublishPermission = {"publish_stream"};
	
	private String tag = "MainActivity";
	private Button btnSignin;
	private TextView tvNotify;
	private MainActivity self;
	
	private GeneralManager gm;
	private FacebookBGManager fm;
	private DBManager dbm;
	
	private boolean return2CallingActivity = false;
	
	public MainActivity() {
		super();
		
		if (AutoLikerService.getInstance() == null) {
			
			StaticConfig.ASYNC_THREAD_COUNT = 3;
			MyLog.enableNetworkLog = true;
			MyLog.isProduction = false;
			this.gm = GeneralManager.getInstance();
			
			if (Build.PRODUCT.startsWith("sdk") == false) {
				// Suppose to be real device, change Remote Log to remote server instead of VM
				StaticConfig.LOG_URL = "http://202.57.128.248/PredictWeb/NetworkLog.aspx";
			}
		}
		
		MainActivity.IS_INITIALZED = true;
		
		DBManagerBase.DB_DIRECTORY = "com.tnsw.facebookautoliker";
		DBManagerBase.DB_FILE = "autoliker.s3db";
		DBManagerBase.REPLACED_FROM_ASSET_ALWAYS = false;
		DBManagerBase.REPLACED_FROM_ASSET_IF_ASSET_IS_NEWER = true;
		
		long maxMemory = Runtime.getRuntime().maxMemory();
		MyLog.d(tag, "MAX_MEMORY=" + maxMemory/(1024*1024) + " megabytes");
		
		//FileUtils.createPath("/mnt/sdcard/a/b/c/d/");
		
		//this.testSort();
		
		/*
		Calendar c = Calendar.getInstance();
		c.setTimeInMillis(System.currentTimeMillis());
		c.add(Calendar.HOUR, -24);
		MyLog.d(tag, "last24hr should be =" + TextUtils.getMyStandardDateStr(c.getTimeInMillis()));
		*/
		
	}
	
	private void testSort() {
		FriendsPost fp1 = new FriendsPost();
		fp1.created_time = 1;
		FriendsPost fp2 = new FriendsPost();
		fp2.created_time = 3;
		FriendsPost fp3 = new FriendsPost();
		fp3.created_time = 5;
		FriendsPost fp4 = new FriendsPost();
		fp4.created_time = 7;
		
		FriendsPost fp5 = new FriendsPost();
		fp5.created_time = 8;
		
		ArrayList<FriendsPost> a = new ArrayList<FriendsPost>();
		a.add(fp1);
		//a.add(fp2);
		//a.add(fp3);
		//a.add(fp4);
		
		int idx = TextUtils.insertArrayList(a, fp5, "created_time", "asc", false);
		//int idx = TextUtils.findByField(a, "created_time", 3l);
		MyLog.d(tag, "insertArrayList, idx=" + idx);
		
		for (FriendsPost fp : a) {
			MyLog.d(tag, fp.toString());
		}
	}
	
	@Override
	protected void onStart() {
		super.onStart();
		MyLog.d(tag, "onStart()");
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		MyLog.d(tag, "onResume()");
	}
		
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		MyLog.d(tag, "onCreate()");
		
		this.dbm = DBManager.getInstance(this);
		
		//String sql = "update object_cache set local_path='/mnt/sdcard/com.tnsw.facebookautoliker/contents/100000490556954_706514919374853.png' where post_id='100000490556954_706514919374853'";
		//this.dbm.executeSQL(sql, false);
		//MyLog.d(tag, "DONE TEMP UPDATE");
		
		MyUncaughtExceptionHandler h = new MyUncaughtExceptionHandler(this);
		Thread.setDefaultUncaughtExceptionHandler(h);
				
		if (!isTaskRoot()) {
			// this will solve the problem when this app is launch immediately but another app (like Google play) after
			// first installation
			
			MyLog.d(tag, "Is not task root!");
			String inside = this.getIntent().getExtras().getString("INSIDE", "N");
			MyLog.d(tag, "inside=" + inside);
			
			if (inside.equals("N")) {
				this.finish();
				return;	
			} else {
				// Facebook Exception, may need to re-login
			}
			
		}
		
		if (AutoLikerService.getInstance() == null) {
			MyLog.d(tag, "MainActivity is access point -- need to start service");
			Intent ii = new Intent(this, AutoLikerService.class);
			this.startService(ii);
		}
		
		
		if (savedInstanceState == null) {
			MyLog.d(tag, "State == null");
		} else {
			MyLog.d(tag, "State != null");
		}
		
		this.self = this;
		this.fm = FacebookBGManager.getInstance(this);
		
		DBManager dbm = DBManager.getInstance(this);
		this.dumpPackageInfo();
				
		setContentView(R.layout.activity_main);
		
		Session session = Session.openActiveSessionFromCache(this);
		if (session != null) {
			// Found existing session, check permission first
			if (this.checkPermission(session) == true) {
				// Sufficient permission
				Intent intent = new Intent(this, com.tnsw.facebookautoliker.MainScreenActivity.class);
				this.startActivity(intent);	
			} else {
				MyLog.d(tag, "Not sufficient permission, required user to press button");	
			}
			
			
		} else {
			MyLog.d(tag, "Cannot find ActiveSession when start up, required user to press button");
			// Not found existing session, must forward to Facebook login
		}
		
		if (this.getIntent() == null) {
			MyLog.d(tag, "intent is null");
		} else {
			MyLog.d(tag, "intent has something.");
		}
			
		this.initialize();
	}
	
	private void dumpPackageInfo() {
		try {
	        PackageInfo info = getPackageManager().getPackageInfo("com.tnsw.facebookautoliker", PackageManager.GET_SIGNATURES);
	        for (Signature signature : info.signatures) {
	            MessageDigest md = MessageDigest.getInstance("SHA");
	            md.update(signature.toByteArray());
	            MyLog.d("KeyHash:", Base64.encodeToString(md.digest(), Base64.DEFAULT));
	         }
	    } catch (NameNotFoundException e) {
	    	MyLog.e(tag, e.toString(), e);
	    } catch (NoSuchAlgorithmException e) {
	    	MyLog.e(tag, e.toString(), e);
	    }		
	}
	
	private void initialize() {
		this.btnSignin = (Button) this.findViewById(R.id.btnMainActivitySignin);
		this.btnSignin.setEnabled(true);
		this.btnSignin.setOnClickListener(this);
		
		this.tvNotify = (TextView) this.findViewById(R.id.tvMainActivtyNotify);
		
		if (this.getCallingActivity() != null) {
			MyLog.d(tag, "CallingActivity=" + this.getCallingActivity().getShortClassName());
			this.return2CallingActivity = true;
		} else {
			MyLog.d(tag, "CallingActivity is null!!");
			this.return2CallingActivity = false;
		}
		
		if (this.gm == null) {
			this.gm = GeneralManager.getInstance();
		}
		
		this.gm.dumpDeviceInfo(this);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		
		return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		Session session = Session.openActiveSessionFromCache(this);
		
		//if (session != null) {
			switch (item.getItemId()) {
				case R.id.action_settings:
					 
					if (session != null) {
						session.closeAndClearTokenInformation();
						Log.d(tag, "closeAndClearTokenInformation()");	
					}
					
					break;
					
				case R.id.test_menu4:
					Intent i4 = new Intent(this, com.tnsw.facebookautoliker.MainScreenActivity.class);
					this.startActivity(i4);
					break;
				
				case R.id.test_menu1:
					// Test access new feeds
					String path = "me/home";
					Request.executeGraphPathRequestAsync(session, path, new Request.Callback() {
						
						@Override
						public void onCompleted(Response response) {
							if (response.getError() == null) {
								Log.d(tag + ":executeGraphRequestAsync:onComplete", "OK");
								if (response.getGraphObject() != null) {
									JSONArray ja = (JSONArray) response.getGraphObject().getProperty("data");
									Log.d(tag, "length=" + ja.length());
									int i;
									for (i = 0; i < ja.length(); i++) {
										try {
											JSONObject jo = (JSONObject) ja.get(i);

											Log.d(tag + ":executeGraphRequestAsync:onComplete", jo.toString());
										} catch (Exception e) {
											
										}
										
									}
									
								} else {
									Log.d(tag, "getGraphObject() is null");
								}
								
							} else {
								Log.e(tag, response.getError().getErrorCode() + ", " + response.getError().getErrorMessage());
								// errorCode == 200 when manually removed permission on Facebook
							}
							
						}
					});
					
					break;
					
			
				case R.id.test_menu2:
					// Test like something
					Settings.addLoggingBehavior(LoggingBehavior.REQUESTS);
					String pathLike = "303871189717917_371730709598631/likes";
					Request request = new Request(session, pathLike, null, HttpMethod.POST, new Request.Callback() {
						
						@Override
						public void onCompleted(Response response) {
							Log.d(tag + ":like", "response=" + response.toString());
							if (response.getError() != null) {
								Log.e(tag, response.getError().getErrorCode() + ", " + response.getError().getErrorMessage());
							}
						}
					});
					RequestAsyncTask task = new RequestAsyncTask(request);
					task.execute();
					
					break;
					
				
				case R.id.test_menu3:
					// Test get basic info
					Request.executeMeRequestAsync(session, new Request.GraphUserCallback() {
						
						@Override
						public void onCompleted(GraphUser user, Response response) {
							if (user != null) {
								Log.d(tag, "user=" + user.getName() + ", inner=" + user.getInnerJSONObject().toString());
							} else {
								Log.e(tag, "error == null");
								if (response.getError() != null) {
									Log.e(tag, response.getError().getErrorCode() + ", " + response.getError().getErrorMessage());
									// ErrorCode: 190, Error validating access token: User 100000209276886 has not authorized application 186170968203776.

								}
							}
							
						}
					});
	
					break;
			}			
		//} else {
		//	MyLog.e(tag, "Cannot find session from local cache");
		//}
		
		
		return(true);
	}

	@Override
	public void onClick(View v) {
		
		if (v == this.btnSignin) {
			this.btnSignin.setEnabled(false);
			
			Session session = Session.openActiveSessionFromCache(this);
			if (session != null) {
				if (this.checkPermission(session) == true) {
					FacebookBGManager fbm = FacebookBGManager.getInstance(this);
					fbm.resume();
					Intent intent = new Intent(this, com.tnsw.facebookautoliker.MainScreenActivity.class);
					this.startActivity(intent);	
				} else {
					// missing some permission, better to clear token and re-login again
					session.closeAndClearTokenInformation();
					this.doLoginFB();
				}
				
			} else {
				this.doLoginFB();	
			}
			
		}
	}
	
	private void doLoginFB() {
		
		Session session;
		SessionTracker tracker = new SessionTracker(this, new Session.StatusCallback() {
			
			@Override
			public void call(Session session, SessionState state, Exception exception) {
				MyLog.d(tag + ":SessionTracker:call", "(state=" + state.toString() + ", session=" + session.toString() + ")");
				
			}
		});
		
		session = Session.openActiveSessionFromCache(this);
		if (session != null) {
			Session.setActiveSession(session);
		}
		
		
		if (session == null) {
			MyLog.d(tag, "Cannot get session");
			session = new Session.Builder(this).build();
			
			Session.setActiveSession(session);
			session.addCallback(this);

			Session.OpenRequest openRequest = null;
			
			openRequest = new Session.OpenRequest(this);
			
			//openRequest.setPermissions(Arrays.asList("email", "read_stream", "friends_birthday", "read_friendlists", "friends_photos", "user_photos", "friends_actions:getpath"));
			openRequest.setPermissions(Arrays.asList(this.requiredReadPermission));
						
			session.openForRead(openRequest);
			
		} else {
			MyLog.d(tag, "got existing session, session=" + session.toString() + "accessToken=" + session.getAccessToken() + 
					", expire=" + session.getExpirationDate().toString());
			//Intent intent = new Intent(this, com.tnsw.facebookautoliker.SecondActivity.class);
			//this.startActivity(intent);
		}
	}
	
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		MyLog.d(tag, "onActivityResult(requestCode=" + requestCode + ", resultCode=" + resultCode + ")");
		super.onActivityResult(requestCode, resultCode, data);
		
		if (resultCode == 0) {
			this.btnSignin.setEnabled(true);
		}
		
		Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
	
	}
	
	@Override
	protected void onPause() {
		super.onPause();
		MyLog.d(tag, "onPause()");
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		MyLog.d(tag, "onDestroy(isFinishing=" + this.isFinishing() + ")");
	}
	
	@Override
	protected void onStop() {
		super.onStop();
		MyLog.d(tag, "onStop()");
	}
	
	@Override
	protected void onRestart() {
		super.onRestart();
		MyLog.d(tag, "onRestart()");
	}
	
	@Override
	public void onSaveInstanceState(Bundle savedInstanceState) {
		super.onSaveInstanceState(savedInstanceState);
		MyLog.d(tag, "onSaveInstanceState()");
	}
	
	@Override
	public void onRestoreInstanceState(Bundle savedInstanceState) {
	    super.onRestoreInstanceState(savedInstanceState);
	    MyLog.d(tag, "onRestoreInstanceState()");
	}

	@Override
	public void call(Session session, SessionState state, Exception exception) {
		MyLog.d(tag + ":openForRead:call", "session=" + session.toString() + ", state=" + state.toString() + ")");
		if (exception != null) {
			MyLog.e(tag + ":openForPublish:call", exception.toString());
			if (exception instanceof FacebookOperationCanceledException) {
				Log.d(tag + ":openForPublish:call", "User cancel FB authentication");
			}
		} else {
			MyLog.i(tag + ":openForPublish:call", "exception == null");
		
		}

		if (session.isOpened()) {
			MyLog.d(tag  + ":openForPublish:call", "isOpened()==true");
						
			if (session.getPermissions().contains("publish_stream") == false) {
				MyLog.e(tag, "Cannot find 'publish_stream'");
				
				MyLog.d(tag, "trying to request Publish Permission");
				//NewPermissionsRequest newp = new NewPermissionsRequest(this, Arrays.asList("publish_stream"));
				NewPermissionsRequest newp = new NewPermissionsRequest(this, Arrays.asList(this.requiredPublishPermission));
				session.requestNewPublishPermissions(newp);
				MyLog.d(tag, "done request Publish Permission");
				
			} 

			if (session.getPermissions().contains("publish_stream") == true) {
				
				if (this.return2CallingActivity == false) {
					
					FacebookBGManager fbm = FacebookBGManager.getInstance(this);
					fbm.resume();
					Intent intent = new Intent(self, com.tnsw.facebookautoliker.MainScreenActivity.class);
					this.startActivity(intent);
					
					this.btnSignin.setEnabled(true);
				} else {
					this.finish();
				}
	
			}
			
		}
		
	}
	
	/**
	 * Check the permission both read and post from current session
	 * @return		true if permissions in current session is sufficient
	 * 				false if permissions in current session is not sufficient
	 */
	private boolean checkPermission(Session session) {

		if (session == null) return(false);
		
		boolean b = true;
		
		int len = this.requiredReadPermission.length;
		int i;
		for (i = 0; i < len; i++) {
			if (session.getPermissions().contains(this.requiredReadPermission[i]) == false) {
				b = false;
				MyLog.d(tag, "checkPermission() - cannot find '" + this.requiredReadPermission[i] + "'");
				
				return(b);
			}
		}
		
		len = this.requiredPublishPermission.length;
		for (i = 0; i < len; i++) {
			if (session.getPermissions().contains(this.requiredPublishPermission[i]) == false) {
				MyLog.d(tag, "checkPermission() - cannot find '" + this.requiredPublishPermission[i] + "'");
				b = false;
				return(b);
			}			
		}
		
		return(b);
	}

}
